package probabilities;

import java.text.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.text.rtf.*;


// This class opens a main window of the application.
public class Gui {
    
    public static void main(String[] args) {
        Gui window = new Gui();
	  window.launchFrame();
    }

    private JFrame f;
    private JTextPane tp;
    private JPanel buttonsPanel;
    
    RTFEditorKit kit;
    StyleContext sc;
    StyledDocument dsd;
    
    private JButton[] buttons = new JButton[] {
        new JButton("Introduction"),
        new JButton("Original function"),
        new JButton("Universal function"),
        new JButton("Results"),
        new JButton("Open project in PDF"),
        new JButton("Open project in .nb")
    };

    private void launchFrame() {
       loadTextPane();
       loadButtonsPanel();
       
       JScrollPane sp = new JScrollPane(tp);
       sp.setPreferredSize(new Dimension( 950, 550 ));
           
       f = new JFrame("Penney Ante");       
       f.add(sp, BorderLayout.NORTH);
       f.add(buttonsPanel, BorderLayout.CENTER);
       f.pack();
       f.setResizable(false);
       f.setLocation(0, 0);
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE );
       f.setVisible(true);
    }

    private void loadTextPane(){
        
       tp = new JTextPane();       
       kit = new RTFEditorKit();
       tp.setEditorKit(kit);
       sc = new StyleContext();          
      
       dsd = new DefaultStyledDocument(sc);
       try{
           Style labelStyle = sc.getStyle(StyleContext.DEFAULT_STYLE);
           StyleConstants.setAlignment(labelStyle, StyleConstants.ALIGN_CENTER);
    
           // When the main window is open for the first time it shows a photo stored in resources directory. 
           Icon icon = new ImageIcon("resources/StartPage.jpg");
           JLabel label = new JLabel(icon);
           StyleConstants.setComponent(labelStyle, label);

           try {
               dsd.insertString(dsd.getLength(), "Ignored", labelStyle);
           } catch (BadLocationException ble) {
               System.err.println(ble.getMessage());
           } 
           
           tp.setDocument(dsd);
                
       } catch (Exception ex) {
           System.out.println(ex.getMessage());            
       }
       
       tp.setEditable(false);    
       tp.setBounds( 0, 0, 950, 550 );
       tp.setBackground(Color.white); 
       tp.setBorder(BorderFactory.createMatteBorder(0,13,0,13,Color.DARK_GRAY));
     }

     private void loadButtonsPanel() {
        buttons[0].addActionListener(new ShowIntroductionHandler());
        buttons[1].addActionListener(new ShowFunctionHandler());
        buttons[2].addActionListener(new ShowFunctionHandler());
        buttons[3].addActionListener(new RunFunctionHandler());
        buttons[4].addActionListener(new OpenProjectHandler());
        buttons[5].addActionListener(new OpenProjectHandler()); 
         
        buttonsPanel =new JPanel();
        buttonsPanel.setLayout(new GridLayout(1, 5));
        for (JButton button : buttons) {
            button.setBackground(Color.BLACK);
            button.setForeground(Color.RED);
            button.setPreferredSize(new Dimension(0, 50));
            buttonsPanel.add(button);
        }
        
     }
     
     // This class displays an introduction content written in rtf and jpg files stored in resources directory. 
     class ShowIntroductionHandler implements ActionListener {
         
        public void actionPerformed(ActionEvent e) {   

            String[] rtfNames = {"Introduction1.rtf", "Introduction2.rtf", "Introduction3.rtf", "Introduction4.rtf"};
            String[] photoNames = {"Introduction1.gif", "Introduction2.gif", "Introduction3.gif", "Introduction4.gif"};
            
            dsd = new DefaultStyledDocument(sc); 
            Style style = sc.getStyle(StyleContext.DEFAULT_STYLE);
            StyleConstants.setAlignment(style, StyleConstants.ALIGN_CENTER);    
            
            InputStream in = null;
            try {
                for (int i=0; i<rtfNames.length; i++) {           
                    
                    File file = new File("resources/" + rtfNames[i]);
                    in = new FileInputStream(file);
                    kit.read(in, dsd ,0);   
                    
                    Icon icon = new ImageIcon("resources/" + photoNames[i]);
                    StyleConstants.setIcon(style, icon);
                    dsd.insertString(dsd.getLength(), "Ignored", style);
                    dsd.insertString(dsd.getLength(), "\n", style);
                                      
                }
                
                tp.setDocument(dsd);
                
            } catch (Exception ex) {
                System.out.println(ex.getMessage());
            } finally {
                try {
                    in.close();
                } catch (IOException ioe) {
                    System.out.println(ioe.getMessage());
                }
            }        
            
        }
     }
            
     // This class displays a code of getProbabilities() function. 
     // The code is written in rtf file stored in resources directory.        
     class ShowFunctionHandler implements ActionListener {
         
        public void actionPerformed(ActionEvent e) {
            String filePath;
            if (e.getSource().equals(buttons[1])) {
                filePath = "resources/OriginalFunction.rtf";
            } else {
                filePath = "resources/UniversalFunction.rtf";
            }
            
            InputStream in = null;
            try {
                File file = new File(filePath);
                in = new FileInputStream(file);
                dsd = new DefaultStyledDocument(sc);
                kit.read(in,dsd,0);
                tp.setDocument(dsd);
            } catch (Exception ex) {
                System.out.println(ex.getMessage());
            } finally {
                try {
                    in.close();
                } catch (IOException ioe) {
                    System.out.println(ioe.getMessage());
                }
            }            
                
        }
     } 
     
     // This class runs the getProbabilities() function for all 28 possible pairs of patterns.
     // It also diplays results and show a short description of the outcom.  
     class RunFunctionHandler implements ActionListener {
        
        // A list used by getPatternsList() function to store all possible patterns of required length.
        // It cannot be declared inside the getPatternsList() function as it is recursive. 
        private ArrayList<String> patternsList = new ArrayList<String>();        
         
        public void actionPerformed(ActionEvent e) {
            
            Probabilities probabilities = new Probabilities();
            
            // Get all possible patterns of required length and store them in two lists.
            getPatternsList("HT", 3, new StringBuffer());            
            ArrayList<String> patterns1 = (ArrayList<String>)patternsList.clone();
            ArrayList<String> patterns2 = (ArrayList<String>)patternsList.clone();
            patternsList.clear();            
            
            // Define Set and Map objects used to store and modify results. 
            Set<String> results = new TreeSet<String>();
            Map<String, Double> result = new TreeMap<String, Double>();
            Map<String, String> properResult = new LinkedHashMap<String, String>();
            Map<String, String> reverseResult = new LinkedHashMap<String, String>();
        
            DecimalFormat df = new DecimalFormat("00.00");
            
            // Run the getProbabilities() function for all 28 possible pairs of patterns. 
            for (String pattern1 : patterns1) {
                
                patterns2.remove(pattern1);
            
                for (String pattern2 : patterns2) {
                    
                    result = probabilities.getProbabilities(pattern1, pattern2);
                    
                    // Format results and store them in results Set.
                    properResult.put( pattern1, df.format(result.get(pattern1)) + "%" );
                    properResult.put( pattern2, df.format(result.get(pattern2)) + "%" );
                    reverseResult.put( pattern2, df.format(result.get(pattern2)) + "%" );
                    reverseResult.put( pattern1, df.format(result.get(pattern1)) + "%" );
                    results.add(properResult.toString());
                    results.add(reverseResult.toString());
                    properResult.clear();
                    reverseResult.clear();
                }
            }
            
            // Set style.
            dsd = new DefaultStyledDocument(sc); 
            MutableAttributeSet standard = new SimpleAttributeSet();
            StyleConstants.setLeftIndent(standard, 13);
            StyleConstants.setRightIndent(standard, 13);
            StyleConstants.setForeground(standard, Color.RED);
            dsd.setParagraphAttributes(0, 0, standard, true); 
            
            InputStream in = null;
            try {
                
                // Show headline.
                File file = new File("resources/Results1.rtf");
                in = new FileInputStream(file);
                kit.read(in,dsd,0);
                dsd.insertString(dsd.getLength(), "\n", standard);
                
                // Display results.
                Iterator line = results.iterator();
                while(line.hasNext()) {    
                    for (int i=1; i<=patterns1.size()-1; i++) {
                        dsd.insertString(dsd.getLength(), line.next() + " ", standard);
                    }
                    dsd.insertString(dsd.getLength(), "\n\n", standard);
                }
                dsd.insertString(dsd.getLength(), "\n", standard);
              
                // Show description of results.
                file = new File("resources/Results2.rtf");
                in = new FileInputStream(file);
                kit.read(in,dsd,0);
                
                tp.setDocument(dsd); 
                
            } catch (Exception ex) {
                System.out.println(ex.getMessage());
            } finally {
                try {
                    in.close();
                } catch (IOException ioe) {
                    System.out.println(ioe.getMessage());
                }
            }          
        
        }
        
        // Recursive function used to generate all patterns of required length.        
        private void getPatternsList(String input, int patternLength, StringBuffer output) {
            
            if (patternLength == 0) {
                patternsList.add(output.toString());            
            } else {
                for (int i = 0; i < input.length(); i++) {
                    output.append(input.charAt(i));
                    getPatternsList(input, patternLength - 1, output);
                    output.deleteCharAt(output.length() - 1);
                }
            } 
            
        }
        
        
     }
     
     // This class opens a project written in Mathematica.
     // The project can be displayed in PDF or CDF form.
     class OpenProjectHandler implements ActionListener {
         
        public void actionPerformed(ActionEvent e) {
            String filePath;
            if (e.getSource().equals(buttons[4])) {
                filePath = "resources/PenneyAnte.pdf";  
            } else {
                filePath = "resources/PenneyAnte.nb";
            }
            
            File file;
            try {
                file = new File(filePath);
                if (file.exists()) { 
                    if (Desktop.isDesktopSupported()) {
			Desktop.getDesktop().open(file);
                    } else {
			System.out.println("Awt Desktop is not supported!");
                    } 
		} else {
                    System.out.println("File does not exist!");
		} 		
	    } catch (Exception ex) {
                ex.printStackTrace();
	    }
        }
     }
     
     
}
